{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 实例8：用Python暴力破解PDF密码"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "所谓暴力破解，其实就是建立一个密码库，将可能的密码都放进去，然后将密码拿出来一个一个地去试，直到正确为止。如同手上有一大串钥匙，但忘记了哪把才是开这个门的，只得一个一个地试。\n",
    "\n",
    "因此暴力破解密码不是万能的，成功率取决于密码的简单程度和密码库是否够强大。当然，还需要更多的时间，毕竟一个钥匙一个钥匙地试，会比直接拿正确的钥匙开锁慢很多。而且这个操作只适合于一些简单的密码，比如一个单词，一串简单的数字等比较弱的密码。\n",
    "\n",
    "下面就用一个示例来演示暴力破解。我们假设这个密码是一个单词，那只需要找到一个英文字典文件，逐个试，就可以找到正确的密码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "破解成功，密码是：pass。\n",
      "Wall time: 8min 22s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "#1.将英文字典的单词读取出来，放入列表\n",
    "dicts=[]\n",
    "dictionary=\"data/dict.txt\"\n",
    "dict_file=open(dictionary)\n",
    "for line in dict_file:\n",
    "    dicts.append(line.strip().lower())\n",
    "\n",
    "#2.将列表dicts中的每个单词拿来试，直到找到密码\n",
    "import PyPDF2 #可从PDF文档提取信息\n",
    "PDFfile=\"data/INV1_sec.pdf\" # 文件路径\n",
    "pdf_obj=open(PDFfile,'rb')# 以二进制读取，将保留PDF中的所有信息\n",
    "pdf_reader=PyPDF2.PdfFileReader(pdf_obj)\n",
    "for i in dicts:\n",
    "    if pdf_reader.decrypt(i): #试密码，若正确，pdf_reader.decrypt(i)结果为True\n",
    "        print(\"破解成功，密码是：{}。\".format(i))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们以实例6里面加密过的PDF文件“INV1_sec.pdf”为例。我们设置的密码是\"pass\"。假设我们忘记了那个密码是什么了，只记得是个单词。然后我们使用字典文件里的单词来逐个试，直到找到密码。\n",
    "\n",
    "首先将英文字典中的每个单词读取出来，并做处理，存入字典`dicts`。我们直接打开dict.txt文件，看见其中的每个单词都是大写，而且每个单词之间有换行，因此需要使用strip()将换行符去除，使用lower()将大写转换成小写。若不做处理，直接放入列表`dicts`，将会是下面酱紫。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['AARHUS\\n',\n",
       " 'AARON\\n',\n",
       " 'ABABA\\n',\n",
       " 'ABACK\\n',\n",
       " 'ABAFT\\n',\n",
       " 'ABANDON\\n',\n",
       " 'ABANDONED\\n',\n",
       " 'ABANDONING\\n',\n",
       " 'ABANDONMENT\\n',\n",
       " 'ABANDONS\\n']"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dicts1=[]\n",
    "dictionary=\"data/dict.txt\"\n",
    "dict_file1=open(dictionary)\n",
    "for line in dict_file1:\n",
    "    dicts1.append(line)\n",
    "dicts1[:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "密码库弄好后，就可以开始逐个去试了。我们导入`PyPDF2`库，以便读取PDF文件。首先打开PDF文件`pdf_obj=open(file,'rb')`，然后读取信息`pdf_reader=PyPDF2.PdfFileReader(pdf_obj)`。\n",
    "\n",
    "最关键的试密码步骤来了，`decrypt()`函数就是干这个的。我们将密码库`dicts`中的每个单词调出来，传入`decrypt()`，如果成功，`decrypt()`将返回1（即True），并将密码打印显示出来，我们就可以用这个密码去打开PDF文件了；如果失败，`decrypt()`将返回0（即False），程序继续执行for循环，继续试下一个，直到成功，或遍历整个密码库。\n",
    "\n",
    "我们可见即便是电脑，整个过程也需要持续8分钟，因此需要泡杯茶难心等待，急不得。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
